home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / archives / com / internet / stik / gls002b5.zoo / transdmn.c < prev    next >
C/C++ Source or Header  |  1997-09-21  |  40KB  |  1,581 lines

  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <support.h>
  7. #include <sys/socket.h>
  8. #include <sys/time.h>
  9. #include <sys/types.h>
  10. #include <netinet/in.h>
  11. #include <netdb.h>
  12. #include <ioctl.h>
  13. #include <fcntl.h>
  14. #include <arpa/nameser.h>    /* for <resolv.h> */
  15. #define __const const        /* grrrr... */
  16. #include <resolv.h>        /* for h_error */
  17. #include <mintbind.h>
  18. #define DAEMON            /* to get "int caller_pid, " */
  19. #include "global.h"
  20. #include "pipe.h"
  21.  
  22.  
  23. /* To facilitate two-step listen/accept without changing the connection
  24.    number, as required by STiK semantics, we make the connection number
  25.    a magic cookie that gets translated to the real fd. */
  26.  
  27. static unsigned char cookie_counter = 0;
  28.  
  29. /* If -DMULTITHREAD is enabled, don't call NEXT_LISTEN_COOKIE() unless
  30.  * you're holding the FD_SEM semaphore. */
  31. #define NEXT_LISTEN_COOKIE()    (int)(('L'<<8)|(cookie_counter++))
  32. #define IS_LISTEN_COOKIE(fd)    ((((fd)>>8)&0xFF)=='L')
  33. #define REAL_FD(pid,fd)        (IS_LISTEN_COOKIE(fd)?get_real_fd(pid,fd):(fd))
  34.  
  35. /* MiNTnet's fcntl(FIONREAD) returns this when the socket shuts down, or
  36.    an error condition occurs, or there's no more to read. */
  37. #define NO_LIMIT    0x7FFFFFFFL
  38.  
  39. typedef struct CIB_chain {
  40.   int the_fd;
  41.   int real_fd;
  42. #ifndef BLOCK_OPEN
  43.   int established;
  44. #endif
  45.   CIB the_CIB;
  46.   struct CIB_chain *next;
  47. } CIB_chain;
  48.  
  49. #if 0
  50. Daemon_Op OP;
  51. Daemon_Retval RET;
  52. #endif
  53. int multithread = 0;
  54. int daemon_pid;
  55. CIB_chain *CIB_list = 0;
  56.  
  57. static int daemon_pipe;
  58.  
  59.  
  60. int init_net()
  61. {
  62.   daemon_pid = Pgetpid();
  63.  
  64.   if (Psem_create(CIB_SEM) < 0) {
  65.     Cconws("Unable to create CIB semaphore\r\n");
  66.     return 0;
  67.   }
  68.  
  69.   /* We own the semaphores when they're created; release them so we can
  70.      re-grab them later */
  71.   Psem_release(CIB_SEM);
  72.  
  73. #ifdef MULTITHREAD
  74.   if (Psem_create(FD_SEM) < 0) {
  75.     Cconws("Unable to create file-descriptor semaphore\r\n");
  76.     return 0;
  77.   }
  78.   Psem_release(FD_SEM);
  79.   {
  80.     /* Enable multithreading if requested. */
  81.     register char *s = do_getvstr(daemon_pid, "MULTITHREAD");
  82.  
  83.     if (!strcmp(s, "1") || !stricmp(s, "ON") || !stricmp(s, "TRUE"))
  84.       multithread = 1;
  85.   }
  86. #endif /* MULTITHREAD */
  87.  
  88.   return 1;
  89. }
  90.  
  91.  
  92. static int dispatch(long msg_ptr)
  93. {
  94.   PMSG pmsg;
  95.   Daemon_Op *OP;
  96.   Daemon_Retval *RET;
  97.  
  98.   /* BUG:  This is a potential race condition; if the parent gets
  99.      another message and writes it over the original before we get a
  100.      chance to copy the original, the original will be lost.
  101.      Unfortunately, I can't think of a solution that doesn't also assume
  102.      that the child thread will go first. */
  103.   pmsg = *(PMSG *)msg_ptr;
  104.   OP = (Daemon_Op *)pmsg.userlong1;
  105.   RET = (Daemon_Retval *)pmsg.userlong2;
  106. #ifdef DEBUG
  107.   LOG(pmsg.pid, DBG_TRACE, "Received op %O", OP->common.op);
  108. #if 0
  109.   debug("sOsd", "Received op ", OP->common.op, " from pid ", pmsg.pid);
  110. #endif
  111. #endif
  112.  
  113.   switch (OP->common.op) {
  114.     case OP_TCP_OPEN:
  115.       RET->ret_int16 = do_TCP_open(pmsg.pid, OP->P_TCP_open.hostaddr,
  116.                    OP->P_TCP_open.port, OP->P_TCP_open.tos,
  117.                    OP->P_TCP_open.obsize);
  118.       break;
  119.     case OP_TCP_CLOSE:
  120.       RET->ret_int16 = do_TCP_close(pmsg.pid, OP->P_TCP_close.fd,
  121.                     OP->P_TCP_close.timeout);
  122.       break;
  123.     case OP_TCP_SEND:
  124.       RET->ret_int16 = do_TCP_send(pmsg.pid, OP->P_TCP_send.fd,
  125.                    OP->P_TCP_send.buf, OP->P_TCP_send.buflen);
  126.       break;
  127.     case OP_TCP_WAIT_STATE:
  128.       RET->ret_int16 = do_TCP_wait_state(pmsg.pid, OP->P_TCP_wait_state.fd,
  129.                      OP->P_TCP_wait_state.state,
  130.                      OP->P_TCP_wait_state.timeout);
  131.       break;
  132.     case OP_UDP_OPEN:
  133.       RET->ret_int16 = do_UDP_open(pmsg.pid, OP->P_UDP_open.hostaddr,
  134.                    OP->P_UDP_open.port);
  135.       break;
  136.     case OP_UDP_CLOSE:
  137.       RET->ret_int16 = do_UDP_close(pmsg.pid, OP->P_UDP_close.fd);
  138.       break;
  139.     case OP_UDP_SEND:
  140.       RET->ret_int16 = do_UDP_send(pmsg.pid, OP->P_UDP_send.fd,
  141.                    OP->P_UDP_send.buf, OP->P_UDP_send.buflen);
  142.       break;
  143.     case OP_CNBYTE_COUNT:
  144.       RET->ret_int16 = do_CNbyte_count(pmsg.pid, OP->P_CNbyte_count.fd);
  145.       break;
  146.     case OP_CNGET_CHAR:
  147.       RET->ret_int16 = do_CNget_char(pmsg.pid, OP->P_CNget_char.fd);
  148.       break;
  149.     case OP_CNGET_NDB:
  150.       RET->ret_NDBptr = do_CNget_NDB(pmsg.pid, OP->P_CNget_NDB.fd);
  151.       break;
  152.     case OP_CNGET_BLOCK:
  153.       RET->ret_int16 = do_CNget_block(pmsg.pid, OP->P_CNget_block.fd,
  154.                       OP->P_CNget_block.buf,
  155.                       OP->P_CNget_block.len);
  156.       break;
  157.     case OP_RESOLVE:
  158.       RET->ret_int16 = do_resolve(pmsg.pid, OP->P_resolve.hostname,
  159.                   OP->P_resolve.realname,
  160.                   OP->P_resolve.addrs,
  161.                   OP->P_resolve.naddrs);
  162.       break;
  163.     case OP_CNGETINFO:
  164.       RET->ret_CIBptr = do_CNgetinfo(pmsg.pid, OP->P_CNgetinfo.fd);
  165.       break;
  166.     case OP_KRMALLOC:
  167.       RET->ret_charptr = do_KRmalloc(pmsg.pid, OP->P_KRmalloc.size);
  168.       break;
  169.     case OP_KRFREE:
  170.       do_KRfree(pmsg.pid, OP->P_KRfree.mem);
  171.       RET->ret_int32 = 0;
  172.       break;
  173.     case OP_KRGETFREE:
  174.       RET->ret_int32 = do_KRgetfree(pmsg.pid, OP->P_KRgetfree.flag);
  175.       break;
  176.     case OP_KRREALLOC:
  177.       RET->ret_charptr = do_KRrealloc(pmsg.pid, OP->P_KRrealloc.mem,
  178.                       OP->P_KRrealloc.newsize);
  179.       break;
  180.     case OP_GETVSTR:
  181.       RET->ret_charptr = do_getvstr(pmsg.pid, OP->P_getvstr.var);
  182.       break;
  183.     case OP_SETVSTR:
  184.       RET->ret_int16 = do_setvstr(pmsg.pid, OP->P_setvstr.var,
  185.                   OP->P_setvstr.value);
  186.       break;
  187.     default:
  188. #ifdef DEBUG
  189.       LOG(pmsg.pid, DBG_ERROR, "in dispatch():  Unrecognized opcode %d",
  190.       OP->common.op);
  191. #if 0
  192.       debug("sd", "in dispatch(): unrecognized opcode ", OP->common.op);
  193. #endif
  194. #endif
  195.       break;
  196.   }
  197. #ifdef DEBUG
  198.   LOG(pmsg.pid, DBG_TRACE, "Sending reply to op %O", OP->common.op);
  199. #if 0
  200.   debug("sOsd", "Sending reply to op ", OP->common.op, " from pid ", pmsg.pid);
  201. #endif
  202. #endif
  203.   Pmsg_send(0xFFFF0000L | pmsg.pid, &pmsg);
  204. }
  205.  
  206.  
  207. void main_loop()
  208. {
  209.   PMSG pmsg;
  210.   int n;
  211.  
  212.   for (;;) {
  213.     n = Pmsg_recv(DMN_MBOX, &pmsg);
  214.     if (n < 0) {
  215. #ifdef DEBUG
  216.       LOG(daemon_pid, DBG_FATAL, "Pmsg() returned %d", n);
  217. #endif
  218.       exit(1);
  219.     }
  220. #ifdef MULTITHREAD
  221.     if (multithread) {
  222.       tfork(dispatch, (long)(&pmsg));
  223.       /* Maximize child thread's chance of copying the pmsg before we
  224.      overwrite it */
  225.       Syield();
  226.     } else
  227. #endif
  228.       dispatch((long)(&pmsg));
  229.   }
  230. }
  231.  
  232.  
  233. static int make_CIB(int caller_pid, int fd, int real_fd, uint16 protocol,
  234.             uint16 lport, uint16 rport, uint32 rhost, int established)
  235. {
  236.   CIB_chain *C;
  237.   int retval = 1;
  238.  
  239.   C = (CIB_chain *)do_KRmalloc(caller_pid, sizeof(CIB_chain));
  240.   if (!C)
  241.     retval = 0;
  242.   else {
  243.     C->the_fd = fd;
  244.     C->real_fd = real_fd;
  245. #ifndef BLOCK_OPEN
  246.     C->established = established;
  247. #endif
  248.     C->the_CIB.protocol = protocol;
  249.     C->the_CIB.lport = lport;
  250.     C->the_CIB.rport = rport;
  251.     C->the_CIB.rhost = rhost;
  252.  
  253.     Psem_obtain(CIB_SEM);        /* Enter MUTEX */
  254.     C->next = CIB_list;
  255.     CIB_list = C;
  256.     Psem_release(CIB_SEM);        /* Leave MUTEX */
  257.   }
  258.  
  259. #ifdef DEBUG
  260.   LOG(caller_pid, DBG_TRACE, "make_CIB(%d{%d}, %d, %d, %d, %A, %d) returns %d",
  261.       fd, real_fd, protocol, lport, rport, rhost, established, retval);
  262. #if 0
  263.   debug("si", "make_CIB() returns ", retval);
  264. #endif
  265. #endif
  266.   return retval;
  267. }
  268.  
  269. static int change_CIB(int caller_pid, int fd, int real_fd, uint16 protocol,
  270.               uint16 lport, uint16 rport, uint32 rhost,
  271.               int established)
  272. {
  273.   CIB_chain *C;
  274.   int retval = 1;
  275.  
  276.   Psem_obtain(CIB_SEM);        /* Enter MUTEX */
  277.   for (C = CIB_list; C; C = C->next) {
  278.     if (C->the_fd == fd) {
  279.       break;
  280.     }
  281.   }
  282.   if (!C)
  283.     retval = 0;
  284.   else {
  285.     C->real_fd = real_fd;
  286. #ifndef BLOCK_OPEN
  287.     C->established = established;
  288. #endif
  289.     C->the_CIB.protocol = protocol;
  290.     C->the_CIB.lport = lport;
  291.     C->the_CIB.rport = rport;
  292.     C->the_CIB.rhost = rhost;
  293.     Psem_release(CIB_SEM);        /* Leave MUTEX */
  294.   }
  295. #ifdef DEBUG
  296.   LOG(caller_pid, DBG_TRACE,
  297.       "change_CIB(%d{%d}, %d, %d, %d, %A, %d) returns %d",
  298.       fd, real_fd, protocol, lport, rport, rhost, established, retval);
  299. #if 0
  300.   debug("si", "make_CIB() returns ", retval);
  301. #endif
  302. #endif
  303.   return retval;
  304. }
  305.  
  306. static CIB *find_CIB(int caller_pid, int fd)
  307. {
  308.   register CIB_chain *C;
  309.   CIB *CC = 0;
  310.  
  311.   Psem_obtain(CIB_SEM);
  312.   for (C = CIB_list; C; C = C->next) {
  313.     if (C->the_fd == fd) {
  314.       CC = &(C->the_CIB);
  315.       break;
  316.     }
  317.   }
  318.   Psem_release(CIB_SEM);
  319.  
  320. #ifdef DEBUG
  321.   LOG(caller_pid, DBG_TRACE, "find_CIB(%d) returns %p", fd, (void *)CC);
  322. #if 0
  323.   debug("sp", "find_CIB() returns ", (void *)CC);
  324. #endif
  325. #endif
  326.   return CC;
  327. }
  328.  
  329. static void remove_CIB(int caller_pid, int fd)
  330. {
  331.   register CIB_chain *C, *C2;
  332.  
  333.   Psem_obtain(CIB_SEM);
  334.   C = CIB_list;
  335.   if (C && C->the_fd == fd) {
  336.     CIB_list = C->next;
  337.     do_KRfree(caller_pid, C);
  338.   } else {
  339.     for (C = CIB_list; C && C->next; C = C->next) {
  340.       if (C->next->the_fd == fd) {
  341.     C2 = C->next;
  342.     C->next = C2->next;
  343.     do_KRfree(caller_pid, C2);
  344.     break;
  345.       }
  346.     }
  347.   }
  348.   Psem_release(CIB_SEM);
  349.  
  350. #ifdef DEBUG
  351.   LOG(caller_pid, DBG_TRACE, "remove_CIB() done");
  352. #if 0
  353.   debug("s", "remove_CIB() done");
  354. #endif
  355. #endif
  356. }
  357.  
  358. #ifndef BLOCK_OPEN
  359. /* Blech blech blech.  I really don't like having to keep state info
  360.    like this, but there appears to be no reliable way to get this info
  361.    on the fly. */
  362. static int is_established(int caller_pid, int fd)
  363. {
  364.   register CIB_chain *C;
  365.  
  366.   Psem_obtain(CIB_SEM);
  367.   for (C = CIB_list; C; C = C->next) {
  368.     if (C->the_fd == fd) {
  369.       break;
  370.     }
  371.   }
  372.   Psem_release(CIB_SEM);
  373.  
  374. #ifdef DEBUG
  375.   LOG(caller_pid, DBG_TRACE, "is_established(%d): %s", fd,
  376.       (!C ? "no such connection?" :
  377.     C->established ? "established" : "not established"));
  378. #if 0
  379.   debug("sdsss", "Connection ", fd, " is ",
  380.     (C->established ? "" : "not "), "established");
  381. #endif
  382. #endif
  383.   return (C ? C->established : 0);
  384. }
  385.  
  386. static void set_establish(int fd)
  387. {
  388.   register CIB_chain *C;
  389.  
  390.   Psem_obtain(CIB_SEM);
  391.   for (C = CIB_list; C; C = C->next) {
  392.     if (C->the_fd == fd) {
  393.       C->established = 1;
  394.       break;
  395.     }
  396.   }
  397.   Psem_release(CIB_SEM);
  398. }
  399. #endif /* BLOCK_OPEN */
  400.  
  401. static int16 get_real_fd(int caller_pid, int16 fd)
  402. {
  403.   register CIB_chain *C;
  404.   int real_fd;
  405.  
  406.   Psem_obtain(CIB_SEM);
  407.   for (C = CIB_list; C; C = C->next) {
  408. #ifdef DEBUG
  409.     LOG(caller_pid, DBG_TRACE,
  410.     "In get_real_fd(%d):  checking CIB for %d{%d}",
  411.     fd, C->the_fd, C->real_fd);
  412. #endif
  413.     if (C->the_fd == fd) {
  414.       real_fd = C->real_fd;
  415.       break;
  416.     }
  417.   }
  418.   Psem_release(CIB_SEM);
  419.  
  420.   if (!C) {
  421. #ifdef DEBUG
  422.     LOG(caller_pid, DBG_ERROR,
  423.     "In get_real_fd(%d):  no matching CIB found", fd);
  424. #endif
  425.     return -1;
  426.   }
  427.  
  428. #ifdef DEBUG
  429.   LOG(caller_pid, DBG_TRACE,
  430.       "get_real_fd(%d) returns underling fd %d", fd, real_fd);
  431. #endif
  432.   return real_fd;
  433. }
  434.  
  435.  
  436.  
  437. /* Incompatibility:  obsize is ignored.  MiNTnet does its own buffer
  438.    handling. */
  439. int16 do_TCP_open(int caller_pid, uint32 hostaddr, int16 port, int16 tos,
  440.           uint16 obsize)
  441. {
  442.   struct sockaddr_in addr;
  443.   int fd;
  444.   size_t scratch = sizeof(struct sockaddr_in);
  445.   int retval;
  446.  
  447. #ifdef MULTITHREAD
  448.   Psem_obtain(FD_SEM);
  449. #endif
  450.  
  451. #ifdef DEBUG
  452.   LOG(caller_pid, DBG_SYSCALL, "Entering TCP_open(%A, %d, %d, %d)",
  453.       hostaddr, port, tos, obsize);
  454. #if 0
  455.   debug("slslslslsisisis", "Entering TCP_open(", (hostaddr>>24), ".",
  456.     (hostaddr>>16)&0xFFL, ".", (hostaddr>>8)&0xFFL, ".", hostaddr&0xFFL,
  457.     ", ", port, ", ", tos, ", ", obsize, ")");
  458. #endif
  459. #endif
  460.   addr.sin_family = AF_INET;
  461.   addr.sin_addr.s_addr = hostaddr;
  462.   addr.sin_port = port;
  463.  
  464.   fd = socket(AF_INET, SOCK_STREAM, 0);
  465.   if (fd < 0) {
  466. #ifdef DEBUG
  467.     int save_errno = errno;
  468.     LOG(caller_pid, DBG_ERROR,
  469.     "In TCP_open(%A, %d, %d, %d):  socket() returns %d (\"%s\")",
  470.     hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  471. #if 0
  472.     debug("sdss", "socket() returns ", errno, ":  ", sys_errlist[errno]);
  473. #endif
  474.     errno = save_errno;
  475. #endif
  476.     switch (errno) {
  477.       case EMFILE:
  478.     retval = E_NOCCB; break;
  479.       case ENOMEM:
  480.     retval = E_NOMEM; break;
  481.       case ENOENT:
  482.       case EAFNOSUPPORT:
  483.       case ESOCKTNOSUPPORT:
  484.       case EPROTONOSUPPORT:
  485.       case EPROTOTYPE:
  486.     retval = -1000 - errno; break;
  487.       default:
  488.     retval = E_CONNECTFAIL; break;
  489.     }
  490. #ifdef DEBUG
  491.     LOG(caller_pid, DBG_ERROR,
  492.     "TCP_open(%A, %d, %d, %d) returns error code %d",
  493.     hostaddr, port, tos, obsize, retval);
  494. #endif
  495.     return retval;
  496.   }
  497.  
  498.   if (hostaddr != 0) {
  499. #ifndef BLOCK_OPEN
  500.     /* From the STiK specs:  "TCP_open() returns immediately, without
  501.        waiting for the connection to establish." */
  502.     if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
  503. #ifdef DEBUG
  504.       int save_errno = errno;
  505.       LOG(caller_pid, DBG_ERROR,
  506.       "In TCP_open(%A, %d, %d, %d): fcntl() returns %d (\"%s\")",
  507.       hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  508.       errno = save_errno;
  509.     LOG(caller_pid, DBG_ERROR,
  510.     "TCP_open(%A, %d, %d, %d) returns error code %d",
  511.     hostaddr, port, tos, obsize, E_CONNECTFAIL);
  512. #endif
  513.       return E_CONNECTFAIL;
  514.     }
  515. #endif
  516.  
  517.     if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  518. #ifdef DEBUG
  519.       int save_errno = errno;
  520.       LOG(caller_pid, DBG_ERROR,
  521.       "In TCP_open(%A, %d, %d, %d):  connect() returns %d (\"%s\")",
  522.       hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  523. #if 0
  524.       debug("sdss", "connect() returns ", errno, ":  ", sys_errlist[errno]);
  525. #endif
  526.       errno = save_errno;
  527. #endif
  528.       switch (errno) {
  529.     case EBADF:
  530.     case EISCONN:
  531.       retval = E_BADHANDLE; break;
  532.     case EINVAL:
  533.       retval = E_LISTEN; break;
  534.     case ETIMEDOUT:
  535.       retval = E_CNTIMEOUT; break;
  536.     case ECONNREFUSED:
  537.       retval = E_REFUSE; break;
  538.     case EALREADY:
  539.     case EINPROGRESS:
  540.     case EINTR:
  541.     case EAFNOSUPPORT:
  542.     case EDESTADDRREQ:
  543.     case EOPNOTSUPP:
  544.       retval = -1000 - errno; break;
  545.     default:
  546.       retval = E_CONNECTFAIL; break;
  547.       }
  548. #ifdef DEBUG
  549.       LOG(caller_pid, DBG_ERROR,
  550.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  551.       hostaddr, port, tos, obsize, retval);
  552. #endif
  553.       return retval;
  554.     }
  555.  
  556.     /* Cobble up the CIB structure for this connection.  The only thing
  557.        we don't yet have is the local port number. */
  558.     
  559.     if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
  560.       int the_err = errno;
  561.  
  562. #ifdef DEBUG
  563.       LOG(caller_pid, DBG_ERROR,
  564.       "In TCP_open(%A, %d, %d, %d):  getsockname() returns %d (\"%s\")",
  565.       hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  566. #if 0
  567.       debug("sdss", "getsockname() returns ", errno, ":  ", sys_errlist[errno]);
  568. #endif
  569. #endif
  570.       close(fd);
  571.       switch (the_err) {
  572.     case EBADF:
  573.       retval = E_BADHANDLE; break;
  574.     case EINVAL:
  575.     case EOPNOTSUPP:
  576.     default:
  577.       retval = -1000 - the_err; break;
  578.       }
  579. #ifdef DEBUG
  580.       LOG(caller_pid, DBG_ERROR,
  581.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  582.       hostaddr, port, tos, obsize, retval);
  583. #endif
  584.       return retval;
  585.     }
  586.     if (!make_CIB(caller_pid, fd, fd, P_TCP, addr.sin_port, port, hostaddr, 0))
  587.     {
  588.       close(fd);
  589. #ifdef DEBUG
  590.       LOG(caller_pid, DBG_ERROR,
  591.       "In TCP_open(%A, %d, %d, %d):  out of memory for make_CIB()",
  592.       hostaddr, port, tos, obsize);
  593.       LOG(caller_pid, DBG_ERROR,
  594.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  595.       hostaddr, port, tos, obsize, E_NOMEM);
  596. #endif
  597.       return E_NOMEM;
  598.     }
  599.  
  600. #ifdef MULTITHREAD
  601.     Psem_release(FD_SEM);
  602. #endif
  603.  
  604. #ifdef DEBUG
  605.     LOG(caller_pid, DBG_SYSCALL,
  606.     "TCP_open(%A, %d, %d, %d) returns socket handle %d{%d}",
  607.     hostaddr, port, tos, obsize, fd, fd);
  608. #if 0
  609.     debug("si", "TCP_open() returns socket handle ", fd);
  610. #endif
  611. #endif
  612.     return fd;
  613.   } else {
  614.     int in_fd;
  615.     size_t addr_size = sizeof(addr);
  616.  
  617.    /* From the STiK specs:  "If rhost is 0, then the connection becomes
  618.       a LISTEN socket, and waits for a connection request from a remote
  619.       host." */
  620.  
  621.     addr.sin_addr.s_addr = INADDR_ANY;
  622.  
  623.     if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  624. #ifdef DEBUG
  625.       int save_errno = errno;
  626.       LOG(caller_pid, DBG_ERROR,
  627.       "In TCP_open(%A, %d, %d, %d):  bind() returns %d (\"%s\")",
  628.       hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  629.       errno = save_errno;
  630. #endif
  631.       switch (errno) {
  632.     case EBADF:
  633.     case EADDRINUSE:
  634.     case EINVAL:
  635.       retval = E_BADHANDLE; break;
  636.     case EAFNOSUPPORT:
  637.     case EACCES:
  638.     case EDESTADDRREQ:
  639.       retval = -1000 - errno; break;
  640.     default:
  641.       retval = E_CONNECTFAIL; break;
  642.       }
  643. #ifdef DEBUG
  644.       LOG(caller_pid, DBG_ERROR,
  645.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  646.       hostaddr, port, tos, obsize, retval);
  647. #endif
  648.       close(fd);
  649.       return retval;
  650.     }
  651.  
  652.     if (listen(fd, 5) < 0) {
  653.       int the_err = errno;
  654.  
  655. #ifdef DEBUG
  656.       LOG(caller_pid, DBG_ERROR,
  657.       "In TCP_open(%A, %d, %d, %d):  listen() returns %d (\"%s\")",
  658.       hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  659. #endif
  660.       close(fd);
  661.       switch (the_err) {
  662.     case EBADF:
  663.       retval = E_BADHANDLE; break;
  664.     case EDESTADDRREQ:
  665.     case EOPNOTSUPP:
  666.     case EINVAL:
  667.       retval = -1000 - the_err; break;
  668.     default:
  669.       retval = E_CONNECTFAIL; break;
  670.       }
  671. #ifdef DEBUG
  672.       LOG(caller_pid, DBG_ERROR,
  673.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  674.       hostaddr, port, tos, obsize, retval);
  675. #endif
  676.       return retval;
  677.     }
  678.  
  679.     /* Cobble up the CIB structure for this connection.  The only thing
  680.        we don't yet have is the local port number. */
  681.     
  682.     if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
  683.       int the_err = errno;
  684.  
  685. #ifdef DEBUG
  686.       LOG(caller_pid, DBG_ERROR,
  687.       "In TCP_open(%A, %d, %d, %d):  getsockname() returns %d (\"%s\")",
  688.       hostaddr, port, tos, obsize, errno, sys_errlist[errno]);
  689. #endif
  690.       close(fd);
  691.       switch (the_err) {
  692.     case EBADF:
  693.       retval = E_BADHANDLE; break;
  694.     case EINVAL:
  695.     case EOPNOTSUPP:
  696.     default:
  697.       retval = -1000 - the_err; break;
  698.       }
  699. #ifdef DEBUG
  700.       LOG(caller_pid, DBG_ERROR,
  701.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  702.       hostaddr, port, tos, obsize, retval);
  703. #endif
  704.       return retval;
  705.     }
  706.  
  707.     in_fd = NEXT_LISTEN_COOKIE();
  708.     if (!make_CIB(caller_pid, in_fd, fd, P_TCP, addr.sin_port, port,
  709.           addr.sin_addr.s_addr, 1))
  710.     {
  711.       close(fd);
  712. #ifdef DEBUG
  713.       LOG(caller_pid, DBG_ERROR,
  714.       "In TCP_open(%A, %d, %d, %d):  out of memory for make_CIB()",
  715.       hostaddr, port, tos, obsize);
  716.       LOG(caller_pid, DBG_ERROR,
  717.       "TCP_open(%A, %d, %d, %d) returns error code %d",
  718.       hostaddr, port, tos, obsize, E_NOMEM);
  719. #endif
  720.       return E_NOMEM;
  721.     }
  722.  
  723. #ifdef MULTITHREAD
  724.     Psem_release(FD_SEM);
  725. #endif
  726.  
  727. #ifdef DEBUG
  728.     LOG(caller_pid, DBG_SYSCALL,
  729.     "TCP_open(%A, %d, %d, %d) returns listen socket handle %d{%d}",
  730.     hostaddr, port, tos, obsize, in_fd, fd);
  731. #endif
  732.     return in_fd;
  733.   }
  734. }
  735.  
  736. /* Incompatibility:  timeout is ignored */
  737. int16 do_TCP_close(int caller_pid, int16 fd, int16 timeout)
  738. {
  739.   int ret;
  740.   int real_fd = REAL_FD(caller_pid, fd);
  741.  
  742. #ifdef MULTITHREAD
  743.   Psem_obtain(FD_SEM);
  744. #endif
  745.  
  746.   remove_CIB(caller_pid, real_fd);
  747.   ret = close(real_fd);
  748. #ifdef DEBUG
  749.   LOG(caller_pid, (ret < 0 ? DBG_ERROR : DBG_SYSCALL),
  750.       "TCP_close(%d{%d}, %d) returns %s%d", fd, real_fd, timeout,
  751.       (ret < 0 ? "error code " : ""), (ret < 0 ? E_BADCLOSE : 0));
  752. #endif
  753.  
  754. #ifdef MULTITHREAD
  755.   Psem_release(FD_SEM);
  756. #endif
  757.  
  758.   if (ret < 0)
  759.     return E_BADCLOSE;
  760.   else return 0;
  761. }
  762.  
  763. /* Incompatibility:  TCP_send() will probably be blocking; after all, I
  764.    can't return E_OBUFFULL in good faith if I don't honor obsize from
  765.    TCP_open(). */
  766. /* Incompatibility:  What is TCP_send() supposed to do if the non-blocking
  767.    TCP_open() hasn't finished?  The STiK specs don't give a clue; I'm
  768.    gonna just turn off O_NDELAY and wait for the connection to establish. */
  769. int16 do_TCP_send(int caller_pid, int16 fd, char* buf, int16 buflen)
  770. {
  771.   int n, tot = 0;
  772.   int real_fd = REAL_FD(caller_pid, fd);
  773.   int retval;
  774.  
  775. #ifdef DEBUG
  776.   LOG(caller_pid, DBG_SYSCALL, "Entering TCP_send(%d{%d}, \"%S\")",
  777.       fd, real_fd, buflen, buf);
  778. #if 0
  779.   debug("sSs", "in TCP_send(\"", buflen, buf, "\")");
  780. #endif
  781. #endif
  782.  
  783. #ifndef BLOCK_OPEN
  784.   if (!is_established(caller_pid, fd))
  785.     do_TCP_wait_state(fd, (IS_LISTEN_COOKIE(fd) ? TLISTEN : TESTABLISH), 0);
  786. #endif
  787.  
  788.   for (;;) {
  789.     n = write(real_fd, buf + tot, buflen - tot);
  790.     if (n < 0) {
  791. #ifdef DEBUG
  792.       int save_errno = errno;
  793.       LOG(caller_pid, DBG_ERROR,
  794.       "In TCP_send(%d{%d}, \"%S\"):  write() returns %d (\"%s\")",
  795.       fd, real_fd, buflen, buf, errno, sys_errlist[errno]);
  796.       errno = save_errno;
  797. #endif
  798.       switch (errno) {
  799.     case EBADF:
  800.       retval = E_BADHANDLE; break;
  801.     case ENOSPC:
  802.       retval = E_NOMEM; break;
  803.     case ENXIO:
  804.       retval = E_LOSTCARRIER; break;
  805.     /* case EAGAIN: */
  806.     case ERANGE:
  807.       retval = E_OBUFFULL; break;
  808.     default:
  809.       retval = -1000 - errno; break;
  810.       }
  811. #ifdef DEBUG
  812.       LOG(caller_pid, DBG_ERROR,
  813.       "TCP_send(%d{%d}, \"%S\") returns error code %d",
  814.       fd, real_fd, buflen, buf, retval);
  815. #endif
  816.       return retval;
  817.     } else {
  818.       tot += n;
  819.       if (tot >= buflen) {
  820. #ifdef DEBUG
  821.     LOG(caller_pid, DBG_SYSCALL,
  822.         "TCP_send(%d{%d}, \"%S\") returns E_NORMAL",
  823.         fd, real_fd, buflen, buf);
  824. #endif
  825.     return E_NORMAL;
  826.       }
  827.     }
  828.   }
  829. }
  830.  
  831. /* Incompatibility:  Yeah, right, like I could reproduce the behavior of
  832.    this function...  This function seems to have two main uses:  with
  833.    TESTABLISH, wait for a non-listen port to finish opening; and with
  834.    TLISTEN, accept() on a listen port. */
  835. int16 do_TCP_wait_state(int caller_pid, int16 fd, int16 state, int16 timeout)
  836. {
  837.   auto fd_set read_set, write_set, except_set;
  838.   struct timeval T;
  839.   int n;
  840.   int real_fd = REAL_FD(caller_pid, fd);
  841.   int retval;
  842.  
  843. #ifdef DEBUG
  844.   LOG(caller_pid, DBG_SYSCALL, "Entering TCP_wait_state(%d{%d}, %d, %d)",
  845.       fd, real_fd, state, timeout);
  846. #if 0
  847.   debug("s", "in TCP_wait_state()");
  848. #endif
  849. #endif
  850.  
  851.   if (IS_LISTEN_COOKIE(fd)) {
  852.     int in_fd;
  853.     struct sockaddr_in addr, addr2;
  854.     size_t addr_size = sizeof(struct sockaddr_in);
  855.  
  856. #ifdef MULTITHREAD
  857.     Psem_obtain(FD_SEM);
  858. #endif
  859.  
  860.     if ((in_fd = accept(real_fd, (struct sockaddr *)&addr, &addr_size)) < 0) {
  861.       int the_err = errno;
  862.  
  863. #ifdef DEBUG
  864.       LOG(caller_pid, DBG_ERROR,
  865.       "In TCP_wait_state(%d{%d}, %d, %d):  accept() returns %d (\"%s\")",
  866.       fd, real_fd, state, timeout, errno, sys_errlist[errno]);
  867. #if 0
  868.       debug("sdss", "accept() returns ", errno, ":  ", sys_errlist[errno]);
  869. #endif
  870. #endif
  871.       switch (the_err) {
  872.     case EBADF:
  873.       retval = E_BADHANDLE; break;
  874.     case EMFILE:
  875.       retval = E_NOCCB; break;
  876.     case ENOMEM:
  877.       retval = E_NOMEM; break;
  878.     case EOPNOTSUPP:
  879.     case EWOULDBLOCK:
  880.     case ECONNABORTED:
  881.     case EINVAL:
  882.     case EINTR:
  883.       retval = -1000 - the_err; break;
  884.     default:
  885.       retval = E_CONNECTFAIL; break;
  886.       }
  887. #ifdef DEBUG
  888.       LOG(caller_pid, DBG_ERROR,
  889.       "TCP_wait_state(%d{%d}, %d, %d) returns error code %d",
  890.       fd, real_fd, state, timeout, retval);
  891. #endif
  892.       return retval;
  893.     }
  894.  
  895.     /* Have to change the CIB to reflect the new state of the socket.
  896.        Part of the data we need came back from accept(); we need to get
  897.        the rest via getsockname(). */
  898.     addr_size = sizeof(struct sockaddr_in);
  899.     if (getsockname(in_fd, (struct sockaddr *)&addr2, &addr_size) < 0) {
  900.       int the_err = errno;
  901.  
  902. #ifdef DEBUG
  903.       LOG(caller_pid, DBG_ERROR,
  904.       "In TCP_wait_state(%d{%d}, %d, %d):  "
  905.       "getsockname() returns %d (\"%s\")",
  906.       fd, real_fd, state, timeout, errno, sys_errlist[errno]);
  907. #if 0
  908.       debug("sdss", "getsockname() returns ", errno, ":  ", sys_errlist[errno]);
  909. #endif
  910. #endif
  911.       close(in_fd);
  912.       switch (the_err) {
  913.     case EBADF:
  914.       retval = E_BADHANDLE; break;
  915.     case EINVAL:
  916.     case EOPNOTSUPP:
  917.     default:
  918.       retval = -1000 - the_err; break;
  919.       }
  920. #ifdef DEBUG
  921.       LOG(caller_pid, DBG_ERROR,
  922.       "TCP_wait_state(%d{%d}, %d, %d) returns error code %d",
  923.       fd, real_fd, state, timeout, retval);
  924. #endif
  925.       return retval;
  926.     }
  927.  
  928.     if (!change_CIB(caller_pid, fd, in_fd, P_TCP, addr2.sin_port,
  929.             addr.sin_port, addr.sin_addr.s_addr, 1))
  930.     {
  931. #ifdef DEBUG
  932.       LOG(caller_pid, DBG_ERROR,
  933.       "In TCP_wait_state(%d{%d}, %d, %d):  unable to update CIB "
  934.       "for listen port",
  935.       fd, real_fd, state, timeout);
  936.       LOG(caller_pid, DBG_ERROR,
  937.       "TCP_wait_state(%d{%d}, %d, %d) returns error code %d",
  938.       fd, real_fd, state, timeout, E_NOMEM);
  939. #endif
  940.       return E_NOMEM;
  941.     }
  942.  
  943.     /* In STiK, an accept() apparently "eats" the listen()'ed socket; we
  944.        emulate that by closing it. */
  945.     close(real_fd);
  946.  
  947. #ifdef MULTITHREAD
  948.     Psem_release(FD_SEM);
  949. #endif
  950.     return E_NORMAL;
  951.   } else {
  952. #ifndef BLOCK_OPEN
  953.     if (is_established(caller_pid, fd))
  954.       return E_NORMAL;
  955.  
  956.     n = fcntl(real_fd, F_GETFL);
  957.     fcntl(real_fd, F_SETFL, n & ~O_NDELAY);
  958.  
  959.     FD_ZERO(&read_set);
  960.     FD_SET(real_fd, &read_set);
  961.     FD_ZERO(&write_set);
  962.     FD_SET(real_fd, &write_set);
  963.     FD_ZERO(&except_set);
  964.     FD_SET(real_fd, &except_set);
  965.     T.tv_sec = timeout;
  966.     T.tv_usec = 0;
  967.  
  968.     n = select(real_fd + 1, &read_set, &write_set, &except_set, &T);
  969.     if (n == 0) {
  970. #ifdef DEBUG
  971.       LOG(caller_pid, DBG_ERROR,
  972.       "TCP_wait_state(%d{%d}, %d, %d) returns E_USERTIMEOUT",
  973.       fd, real_fd, state, timeout);
  974. #endif
  975.       return E_USERTIMEOUT;
  976.     } if (n > 0) {
  977.       set_establish(fd);
  978.       return E_NORMAL;
  979.     }
  980. #ifdef DEBUG
  981.     {
  982.       int save_errno = errno;
  983.       LOG(caller_pid, DBG_ERROR,
  984.       "In TCP_wait_state(%d{%d}, %d, %d): select() returned %d (\"%s\")",
  985.       fd, real_fd, state, timeout, errno, sys_errlist[errno]);
  986.       errno = save_errno;
  987.     }
  988. #endif
  989.     switch (errno) {
  990.       case EBADF:
  991.     retval = E_BADHANDLE; break;
  992.       case EINTR:
  993.       case EINVAL:
  994.       default:
  995.     retval = -1000 - errno; break;
  996.     }
  997. #ifdef DEBUG
  998.     LOG(caller_pid, DBG_ERROR,
  999.     "TCP_wait_state(%d{%d}, %d, %d) returns error code %d",
  1000.     fd, real_fd, state, timeout, retval);
  1001. #endif
  1002.       return retval;
  1003. #else
  1004.     return E_NORMAL;
  1005. #endif /* BLOCK_OPEN */
  1006.   }
  1007. }
  1008.  
  1009. int16 do_UDP_open(int caller_pid, uint32 hostaddr, int16 port)
  1010. {
  1011.   struct sockaddr_in addr;
  1012.   int fd;
  1013.   size_t scratch = sizeof(struct sockaddr_in);
  1014.   int retval;
  1015.  
  1016. #ifdef DEBUG
  1017.   LOG(caller_pid, DBG_SYSCALL, "Entering UDP_open(%A, %d)",
  1018.       hostaddr, port);
  1019. #if 0
  1020.   debug("s", "in UDP_open()");
  1021. #endif
  1022. #endif
  1023.  
  1024. #ifdef MULTITHREAD
  1025.   Psem_obtain(FD_SEM);
  1026. #endif
  1027.  
  1028.   addr.sin_family = AF_INET;
  1029.   addr.sin_addr.s_addr = hostaddr;
  1030.   addr.sin_port = port;
  1031.   memset(addr.sin_zero, 0, 8);
  1032.  
  1033.   fd = socket(AF_UNIX, SOCK_DGRAM, IPPROTO_UDP);
  1034.   if (fd < 0) {
  1035. #ifdef DEBUG
  1036.     int save_errno = errno;
  1037.     LOG(caller_pid, DBG_ERROR,
  1038.     "In UDP_open(%A, %d):  socket() returned %d (\"%s\")",
  1039.     hostaddr, port, errno, sys_errlist[errno]);
  1040.     errno = save_errno;
  1041. #endif
  1042.     switch (errno) {
  1043.       case EMFILE:
  1044.     retval = E_NOCCB; break;
  1045.       case ENOMEM:
  1046.     retval = E_NOMEM; break;
  1047.       case ENOENT:
  1048.       case EAFNOSUPPORT:
  1049.       case ESOCKTNOSUPPORT:
  1050.       case EPROTONOSUPPORT:
  1051.       case EPROTOTYPE:
  1052.         retval = -1000 - errno; break;
  1053.       default:
  1054.     retval = E_CONNECTFAIL; break;
  1055.     }
  1056. #ifdef DEBUG
  1057.     LOG(caller_pid, DBG_ERROR,
  1058.     "UDP_open(%A, %d) returns error code %d",
  1059.     hostaddr, port, retval);
  1060. #endif
  1061.     return retval;
  1062.   }
  1063.  
  1064.   if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  1065.     int the_err = errno;
  1066.  
  1067.     close(fd);
  1068. #ifdef DEBUG
  1069.     LOG(caller_pid, DBG_ERROR,
  1070.     "In UDP_open(%A, %d):  socket() returned %d (\"%s\")",
  1071.     hostaddr, port, the_err, sys_errlist[the_err]);
  1072. #endif
  1073.     switch (the_err) {
  1074.       case EBADF:
  1075.       case EISCONN:
  1076.     retval = E_BADHANDLE; break;
  1077.       case EINVAL:
  1078.     retval = E_LISTEN; break;
  1079.       case ETIMEDOUT:
  1080.     retval = E_CNTIMEOUT; break;
  1081.       case ECONNREFUSED:
  1082.     retval = E_REFUSE; break;
  1083.       case EALREADY:
  1084.       case EINPROGRESS:
  1085.       case EINTR:
  1086.     retval = fd; break;
  1087.       case EAFNOSUPPORT:
  1088.       case EDESTADDRREQ:
  1089.       case EOPNOTSUPP:
  1090.     retval = -1000 - the_err; break;
  1091.       default:
  1092.     retval = E_CONNECTFAIL; break;
  1093.     }
  1094. #ifdef DEBUG
  1095.     LOG(caller_pid, DBG_ERROR,
  1096.     "UDP_open(%A, %d) returns error code %d",
  1097.     hostaddr, port, retval);
  1098. #endif
  1099.     return retval;
  1100.   }
  1101.  
  1102.   /* Cobble up the CIB structure for this connection.  The only thing
  1103.      we don't yet have is the local port number. */
  1104.   
  1105.   if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
  1106.     int the_err = errno;
  1107.  
  1108.     close(fd);
  1109. #ifdef DEBUG
  1110.     LOG(caller_pid, DBG_ERROR,
  1111.     "In UDP_open(%A, %d):  getsockname() returned %d (\"%s\")",
  1112.     hostaddr, port, the_err, sys_errlist[the_err]);
  1113. #endif
  1114.     switch (the_err) {
  1115.       case EBADF:
  1116.     retval = E_BADHANDLE; break;
  1117.       case EINVAL:
  1118.       case EOPNOTSUPP:
  1119.       default:
  1120.     retval = -1000 - the_err; break;
  1121.     }
  1122. #ifdef DEBUG
  1123.     LOG(caller_pid, DBG_ERROR,
  1124.     "UDP_open(%A, %d) returns error code %d",
  1125.     hostaddr, port, retval);
  1126. #endif
  1127.     return retval;
  1128.   }
  1129.   if (!make_CIB(caller_pid, fd, fd, P_UDP, addr.sin_port, port, hostaddr, 1)) {
  1130.     close(fd);
  1131. #ifdef DEBUG
  1132.     LOG(caller_pid, DBG_ERROR,
  1133.     "In UDP_open(%A, %d):  out of memory for make_CIB()", hostaddr, port);
  1134.     LOG(caller_pid, DBG_ERROR,
  1135.     "UDP_open(%A, %d) returns error code %d",
  1136.     hostaddr, port, E_NOMEM);
  1137. #endif
  1138.     return E_NOMEM;
  1139.   }
  1140.  
  1141. #ifdef MULTITHREAD
  1142.   Psem_release(FD_SEM);
  1143. #endif
  1144.  
  1145. #ifdef DEBUG
  1146.   LOG(caller_pid, DBG_SYSCALL,
  1147.       "UDP_open(%A, %d) returns port %d", hostaddr, port, fd);
  1148. #endif
  1149.   return fd;
  1150. }
  1151.  
  1152. int16 do_UDP_close(int caller_pid, int16 fd)
  1153. {
  1154.   int ret;
  1155.   int real_fd = REAL_FD(caller_pid, fd);
  1156.  
  1157. #ifdef DEBUG
  1158.   LOG(caller_pid, DBG_SYSCALL, "Entering UDP_close(%d{%d})", fd, real_fd);
  1159. #if 0
  1160.   debug("s", "in UDP_close()");
  1161. #endif
  1162. #endif
  1163.  
  1164. #ifdef MULTITHREAD
  1165.   Psem_obtain(FD_SEM);
  1166. #endif
  1167.   remove_CIB(caller_pid, fd);
  1168.   ret = close(real_fd);
  1169. #ifdef MULTITHREAD
  1170.   Psem_release(FD_SEM);
  1171. #endif
  1172.  
  1173.   if (ret < 0) {
  1174. #ifdef DEBUG
  1175.     LOG(caller_pid, DBG_ERROR,
  1176.     "UDP_open(%d{%d}) returns error code %d",
  1177.     fd, real_fd, E_BADCLOSE);
  1178. #endif
  1179.     return E_BADCLOSE;
  1180.   } else return 0;
  1181. }
  1182.  
  1183. int16 do_UDP_send(int caller_pid, int16 fd, char* buf, int16 buflen)
  1184. {
  1185.   int n, tot = 0;
  1186.   int real_fd = REAL_FD(caller_pid, fd);
  1187.   int retval;
  1188.  
  1189. #ifdef DEBUG
  1190.   LOG(caller_pid, DBG_SYSCALL, "Entering UDP_send(%d{%d}, \"%S\")",
  1191.       fd, real_fd, buflen, buf);
  1192. #if 0
  1193.   debug("s", "in UDP_send()");
  1194. #endif
  1195. #endif
  1196.   n = write(real_fd, buf + tot, buflen - tot);
  1197.   if (n < 0) {
  1198. #ifdef DEBUG
  1199.     int save_errno = errno;
  1200.     LOG(caller_pid, DBG_ERROR,
  1201.     "In UDP_send(%d{%d}, \"%S\"):  write() returned %d (\"%s\")",
  1202.     fd, real_fd, buflen, buf, errno, sys_errlist[errno]);
  1203.     errno = save_errno;
  1204. #endif
  1205.     switch (errno) {
  1206.       case EBADF:
  1207.     retval = E_BADHANDLE; break;
  1208.       case ENOSPC:
  1209.     retval = E_NOMEM; break;
  1210.       case ENXIO:
  1211.     retval = E_LOSTCARRIER; break;
  1212.       case ERANGE:
  1213.     retval = E_OBUFFULL; break;
  1214.       default:
  1215.     retval = -1000 - errno; break;
  1216.     }
  1217. #ifdef DEBUG
  1218.     LOG(caller_pid, DBG_ERROR,
  1219.     "UDP_send(%d{%d}, \"%S\") returns error code %d",
  1220.     fd, real_fd, buflen, buf, retval);
  1221. #endif
  1222.     return retval;
  1223.   } else {
  1224.     return E_NORMAL;
  1225.   }
  1226. }
  1227.  
  1228. /* This is just an estimate, but it should work. */
  1229. int16 do_CNbyte_count(int caller_pid, int16 fd)
  1230. {
  1231.   long l;
  1232.   int real_fd = REAL_FD(caller_pid, fd);
  1233.  
  1234.   if (fcntl(real_fd, FIONREAD, &l) < 0) {
  1235. #ifdef DEBUG
  1236.     int save_errno = errno;
  1237.     LOG(caller_pid, DBG_ERROR,
  1238.     "In CNbyte_count(%d{%d}): fcntl() returns %d (\"%s\")",
  1239.     fd, real_fd, errno, sys_errlist[errno]);
  1240.     errno = save_errno;
  1241.     LOG(caller_pid, DBG_ERROR,
  1242.     "CNbyte_count(%d{%d}) returns error code %d",
  1243.     fd, real_fd, -1000 - errno);
  1244. #endif
  1245.     return -1000 - errno;
  1246.   }
  1247.   if (l == NO_LIMIT) {
  1248. #ifndef BLOCK_OPEN
  1249.     /* Tricky.  This could be either EOF or the connection not
  1250.        established.  In the latter case, we have the "0 or E_NODATA?"
  1251.        puzzler from below. */
  1252.     if (!is_established(caller_pid, fd)) {
  1253. #ifdef DEBUG
  1254.       LOG(caller_pid, DBG_SYSCALL, "CNbyte_count(%d{%d}) returns 0",
  1255.       fd, real_fd);
  1256. #endif
  1257.       return 0;
  1258.     }
  1259. #endif
  1260.     return E_EOF;
  1261.   }
  1262.   /* Now here's a puzzler.  If there's no data available should I return
  1263.      0 or E_NODATA?  Dan Ackerman's mailer assumes the former, so that's
  1264.      what I'll do. */
  1265.   if (l == 0) {
  1266. #ifdef DEBUG
  1267.     LOG(caller_pid, DBG_SYSCALL, "CNbyte_count(%d{%d}) returns 0",
  1268.     fd, real_fd);
  1269. #endif
  1270.     /* Here's a sneaky trick:  If there's no data, surrender the rest of
  1271.        our timeslice so that the STiK app doesn't eat all CPU time
  1272.        spinning its wheels. */
  1273.     Syield();
  1274.     return 0;
  1275.   }
  1276. #ifdef DEBUG
  1277.   LOG(caller_pid, DBG_SYSCALL, "CNbyte_count(%d{%d}) returns %l",
  1278.       fd, real_fd, l);
  1279. #endif
  1280. #ifndef BLOCK_OPEN
  1281.   /* I really don't like doing this here, since this function will
  1282.      likely be called in a tight loop, but it has to be done, and this
  1283.      is about the only place I can do it. */
  1284.   set_establish(fd);
  1285. #endif
  1286.   return l;
  1287. }
  1288.  
  1289. /* There should probably be a more efficient way of doing this than
  1290.    calling read() */
  1291. int16 do_CNget_char(int caller_pid, int16 fd)
  1292. {
  1293.   char c;
  1294.   int n;
  1295.   int real_fd = REAL_FD(caller_pid, fd);
  1296.   int retval;
  1297.  
  1298.   n = read(real_fd, &c, 1);
  1299.   if (n > 0) {
  1300. #ifndef BLOCK_OPEN
  1301.     /* Again, I don't really like doing this here, but I don't think I
  1302.        can avoid it. */
  1303.     set_establish(fd);
  1304. #endif
  1305. #ifdef DEBUG
  1306.     LOG(caller_pid, DBG_SYSCALL, "CNget_char(%d{%d}) returns '%c' (%x)",
  1307.     fd, real_fd, c, (unsigned)c);
  1308. #endif
  1309.     return c;
  1310.   }
  1311.   if (n == 0) {
  1312. #ifdef DEBUG
  1313.     LOG(caller_pid, DBG_SYSCALL, "CNget_char(%d{%d}) returns EOF",
  1314.     fd, real_fd);
  1315. #endif
  1316.     return E_EOF;
  1317.   }
  1318. #ifdef DEBUG
  1319.   {
  1320.     int save_errno = errno;
  1321.     LOG(caller_pid, DBG_ERROR,
  1322.     "In CNget_char(%d{%d}):  read() returns %d (\"%s\")",
  1323.     fd, real_fd, errno, sys_errlist[errno]);
  1324.     errno = save_errno;
  1325.   }
  1326. #endif
  1327.   switch (errno) {
  1328.     case EWOULDBLOCK:
  1329.       retval = E_NODATA; break;
  1330.     case EBADF:
  1331.       retval = E_BADHANDLE; break;
  1332.     default:
  1333.       retval = -1000 - errno; break;
  1334.   }
  1335. #ifdef DEBUG
  1336.   LOG(caller_pid, DBG_ERROR,
  1337.       "CNget_char(%d{%d}) returns error code %d",
  1338.       fd, real_fd, retval);
  1339. #endif
  1340.   return retval;
  1341. }
  1342.  
  1343. /* We fake this by reading whatever is there and building a a fake NDB
  1344.    for it */
  1345. NDB* do_CNget_NDB(int caller_pid, int16 fd)
  1346. {
  1347.   int bufsize = do_CNbyte_count(caller_pid, fd);
  1348.   char *buf;
  1349.   NDB *ndb = 0;
  1350.   int real_fd = REAL_FD(caller_pid, fd);
  1351.  
  1352.   if (bufsize <= 0) {
  1353. #ifdef DEBUG
  1354.     LOG(caller_pid, DBG_ERROR,
  1355.     "In CNget_NDB(%d{%d}): no data available; returning 0",
  1356.     fd, real_fd);
  1357. #endif
  1358.     return 0;
  1359.   }
  1360.   buf = do_KRmalloc(caller_pid, bufsize);
  1361.   if (!buf) {
  1362. #ifdef DEBUG
  1363.     LOG(caller_pid, DBG_ERROR,
  1364.     "In CNget_NDB(%d{%d}): out of memory for NDB data; returning 0",
  1365.     fd, real_fd);
  1366. #endif
  1367.     return 0;
  1368.   }
  1369.   ndb = (NDB *)do_KRmalloc(caller_pid, sizeof(NDB));
  1370.   if (!ndb) {
  1371.     do_KRfree(caller_pid, buf);
  1372. #ifdef DEBUG
  1373.     LOG(caller_pid, DBG_ERROR,
  1374.     "In CNget_NDB(%d{%d}): out of memory for NDB; returning 0",
  1375.     fd, real_fd);
  1376. #endif
  1377.     return 0;
  1378.   }
  1379.   bufsize = read(real_fd, buf, bufsize);
  1380.   if (bufsize <= 0) {
  1381.     do_KRfree(caller_pid, buf);
  1382.     do_KRfree(caller_pid, (char *)ndb);
  1383. #ifdef DEBUG
  1384.     LOG(caller_pid, DBG_ERROR,
  1385.     "In CNget_NDB(%d{%d}): no data read; returning 0",
  1386.     fd, real_fd);
  1387. #endif
  1388.     return 0;
  1389.   }
  1390.   ndb->ptr = ndb->ndata = buf;
  1391.   ndb->len = bufsize;
  1392.   ndb->next = 0;
  1393. #ifdef DEBUG
  1394.   LOG(caller_pid, DBG_TRACE, "CNget_NDB(%d{%d}) reads data |%s|",
  1395.       fd, real_fd, ndb->ndata);
  1396.   LOG(caller_pid, DBG_SYSCALL, "CNget_NDB(%d{%d}) reads %d bytes, returns %p",
  1397.       fd, real_fd, ndb->len, (void *)ndb);
  1398. #endif
  1399.   return ndb;
  1400. }
  1401.  
  1402. /* Incompatibility:  CNget_block() is blocking, because there's no way
  1403.    to say to MiNTnet, "If you can't fill the entire buffer in one try,
  1404.    don't read anything" */
  1405. int16 do_CNget_block(int caller_pid, int16 fd, char* buf, int16 len)
  1406. {
  1407.   int n, tot = 0;
  1408.   int real_fd = REAL_FD(caller_pid, fd);
  1409.   int retval;
  1410.  
  1411. #ifndef BLOCK_OPEN
  1412.   if (!is_established(caller_pid, fd))
  1413.     do_TCP_wait_state(fd, 0, 0);
  1414. #endif
  1415.  
  1416.   for (;;) {
  1417.     n = read(real_fd, buf + tot, len - tot);
  1418.     if (n > 0) {
  1419.       tot += n;
  1420.       if (tot >= len) {
  1421. #ifdef DEBUG
  1422.     LOG(caller_pid, DBG_TRACE,
  1423.         "CNget_block(%d{%d}, %d) reads |%s|",
  1424.         fd, real_fd, len, buf);
  1425.     LOG(caller_pid, DBG_SYSCALL,
  1426.         "CNget_block(%d{%d}, %d) returns length %d",
  1427.         fd, real_fd, len, tot);
  1428. #endif
  1429.     return tot;
  1430.       }
  1431.     } else if (n == 0) {
  1432.       /* Incompatibility:  If we read part of the buffer before getting
  1433.      the EOF, there's no way to "unread" the read data.  I'm torn
  1434.      between returning the number of bytes actually read and
  1435.      trusting the caller to notice, or returning E_EOF and
  1436.      discarding the partial buffer.  For now, I'll do the former. */
  1437. #ifdef DEBUG
  1438.     LOG(caller_pid, DBG_TRACE,
  1439.         "CNget_block(%d{%d}, %d) reads partial buffer |%s|",
  1440.         fd, real_fd, len, buf);
  1441.     LOG(caller_pid, DBG_SYSCALL,
  1442.         "CNget_block(%d{%d}, %d) returns partial buffer length %d",
  1443.         fd, real_fd, len, tot);
  1444. #endif
  1445.       return tot;
  1446.     } else {
  1447. #ifdef DEBUG
  1448.       int save_errno = errno;
  1449.       LOG(caller_pid, DBG_ERROR,
  1450.       "In CNget_block(%d{%d}, %d):  read() returns %d (\"%s\")",
  1451.       fd, real_fd, len, errno, sys_errlist[errno]);
  1452.       errno = save_errno;
  1453. #endif
  1454.       switch (errno) {
  1455.     case EWOULDBLOCK:
  1456.       retval = E_NODATA; break;
  1457.     case EBADF:
  1458.       retval = E_BADHANDLE; break;
  1459.     default:
  1460.       retval = -1000 - errno; break;
  1461.       }
  1462. #ifdef DEBUG
  1463.       LOG(caller_pid, DBG_ERROR,
  1464.       "CNget_block(%d{%d}, %d) returns error code %d",
  1465.       fd, real_fd, len, retval);
  1466. #endif
  1467.       return retval;
  1468.     }
  1469.   }
  1470. }
  1471.  
  1472. int16 do_resolve(int caller_pid, char *hostname, char **realname,
  1473.          uint32 *addrs, int16 naddrs)
  1474. {
  1475.   register struct hostent *H = 0;
  1476.   register char **raddr;
  1477.   register int i;
  1478.   int retval;
  1479.  
  1480. #ifdef DEBUG
  1481.   LOG(caller_pid, DBG_SYSCALL, "Entering resolve(\"%s\", %p, %p, %d)",
  1482.       hostname, (void *)realname, (void *)addrs, naddrs);
  1483. #if 0
  1484.   debug("ssspspsis", "in resolve(\"", hostname, "\", ", (void *)realname,
  1485.              ", ", (void *)addrs, ", ", naddrs, ")");
  1486. #endif
  1487. #endif
  1488.   H = gethostbyname(hostname);
  1489.   if (!H) {
  1490. #ifdef DEBUG
  1491.     LOG(caller_pid, DBG_ERROR,
  1492.     "In resolve(\"%s\", %p, %p, %d):  gethostbyname() returns %d (\"%s\")",
  1493.     hostname, (void *)realname, (void *)addrs, naddrs,
  1494.     h_errno, sys_errlist[h_errno]);
  1495. #if 0
  1496.     debug("s", "gethostbyname() returns NULL");
  1497. #endif
  1498. #endif
  1499.     switch (h_errno) {
  1500.       case HOST_NOT_FOUND:
  1501.     retval = E_NOHOSTNAME; break;
  1502.       case NO_DATA:
  1503.     retval = E_DNSNOADDR; break;
  1504.       case TRY_AGAIN:
  1505.       case NO_RECOVERY:
  1506.       default:
  1507.     retval = E_CANTRESOLVE; break;
  1508.     }
  1509. #ifdef DEBUG
  1510.     LOG(caller_pid, DBG_ERROR,
  1511.     "resolve(\"%s\", %p, %p, %d) returns error code %d",
  1512.     hostname, (void *)realname, (void *)addrs, naddrs, retval);
  1513. #endif
  1514.     return retval;
  1515.   }
  1516. #ifdef DEBUG
  1517.   LOG(caller_pid, DBG_TRACE,
  1518.       "In resolve(\"%s\", %p, %p, %d):  gethostbyname() returns %p",
  1519.       hostname, (void *)realname, (void *)addrs, naddrs, (void *)H);
  1520. #endif
  1521.  
  1522.   if (realname) {
  1523. #ifdef DEBUG
  1524.     LOG(caller_pid, DBG_TRACE, "Copying name \"%s\"", H->h_name);
  1525. #endif
  1526.     *realname = do_KRmalloc(caller_pid, strlen(H->h_name) + 1);
  1527.     strcpy(*realname, H->h_name);
  1528.   }
  1529.   /* BUG:  assumes addresses returned have type struct in_addr */
  1530.   for (i = 0, raddr = H->h_addr_list; *raddr && i < naddrs; i++, raddr++) {
  1531. #ifdef DEBUG
  1532.     LOG(caller_pid, DBG_TRACE, "Copying address %A to array element %d",
  1533.     ((struct in_addr *)(*raddr))->s_addr, i);
  1534. #endif
  1535.     addrs[i] = ((struct in_addr *)(*raddr))->s_addr;
  1536.   }
  1537.  
  1538. #ifdef DEBUG
  1539.   LOG(caller_pid, DBG_SYSCALL,
  1540.       "resolve(\"%s\", %p, %p, %d) returns %d",
  1541.       hostname, (void *)realname, (void *)addrs, naddrs, i);
  1542. #endif
  1543.   return i;
  1544. }
  1545.  
  1546. /* (possible) Incompatibility:  It is possible, at least in theory, for
  1547.    find_CIB() to return NULL; the STiK specs seem to imply that this
  1548.    cannot happen, so the receiving app probably doesn't check for it.
  1549.    In practice, find_CIB() should not return NULL, except for file
  1550.    descriptors that aren't sockets opened by GlueSTiK. */
  1551. CIB* do_CNgetinfo(int caller_pid, int16 fd)
  1552. {
  1553.   register CIB *C;
  1554.  
  1555. #ifdef DEBUG
  1556.   LOG(caller_pid, DBG_SYSCALL, "Entering CNgetinfo(%d)", fd);
  1557. #if 0
  1558.   debug("s", "in do_CNgetinfo()");
  1559. #endif
  1560. #endif
  1561.  
  1562.   C =  find_CIB(caller_pid, fd);
  1563.  
  1564. #ifdef DEBUG
  1565.   LOG(caller_pid, (!C ? DBG_ERROR : DBG_SYSCALL),
  1566.       "CNgetinfo(%d) returns %p", fd, (void *)C);
  1567. #endif
  1568.   return C;
  1569. }
  1570.  
  1571.  
  1572. void cleanup_net()
  1573. {
  1574.   Psem_obtain(CIB_SEM);
  1575.   Psem_destroy(CIB_SEM);
  1576. #ifdef MULTITHREAD
  1577.   Psem_obtain(FD_SEM);
  1578.   Psem_destroy(FD_SEM);
  1579. #endif
  1580. }
  1581.